/*
@file: ast.h
@author: ZZH
@date: 2022-03-09
@info: 抽象语法树
*/
#pragma once
#include <QString>
#include <QList>
#include <cmath>
#include "calculator.h"
#include "libFun.h"

// clang-format on

class ASTExpress_t
{
private:

protected:
    using BasicType = CalculatorConf::BasicType;

public:
    ASTExpress_t() {}
    virtual ~ASTExpress_t() {}

    virtual void calculate(BasicType* output) const = 0;
    virtual bool isDirty(void) const { return false; }
};

class ASTAdaptor_t: public ASTExpress_t
{
private:

protected:
    ASTExpress_t* child;

public:
    ASTAdaptor_t(ASTExpress_t* pChild): child(pChild) {}
    // adaptor在被析构时不释放子节点,因为它的作用就是自动断开释放链
    virtual ~ASTAdaptor_t() {}

    virtual void calculate(BasicType* output) const override { this->child->calculate(output); }
    virtual bool isDirty(void) const override;
};

class ASTFunctionCall_t: public ASTExpress_t
{
private:

public:
    typedef void (*pf)(pFunCallArg_t pArgs, BasicType* output);

    typedef struct
    {
        pf pFunc;
        unsigned int numOfArg;
    } calFunc_t;

    // typedef void (*calFunc_t)(pFunCallArg_t pArgs, BasicType* output);

protected:
    pf Calcb;
    QList<ASTExpress_t*>* args;

public:
    ASTFunctionCall_t(pf fun, QList<ASTExpress_t*>* args): Calcb(fun), args(args) {}
    virtual ~ASTFunctionCall_t()
    {
        if (this->args) {
            for (auto exp : *this->args) delete exp;

            delete this->args;
        }
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        if (nullptr != this->args) {
            for (auto exp : *this->args) {
                if (exp->isDirty())
                    return true;
            }
        }

        return false;
    }
};

class ASTNumber_t: public ASTExpress_t
{
private:

protected:
    BasicType value;

public:
    ASTNumber_t(BasicType f): value(f) {}
    virtual ~ASTNumber_t() {}

    virtual void calculate(BasicType* output) const override
    {
        if (nullptr != output) {
            int allNum = Calculator_t::getInst().getTotolPoint();
            for (int i = 0; i < allNum; i++) output[i] = this->value;
        }
    }
};

class ASTDynamicNumber_t: public ASTExpress_t
{
private:

public:
    typedef enum
    {
        VariableT,
        VariableN,
        VariableFS,
        VariableI,
    } DynNumber_t;

protected:
    const DynNumber_t type;

public:
    ASTDynamicNumber_t(const DynNumber_t t): type(t) {}
    virtual ~ASTDynamicNumber_t() {}

    virtual void calculate(BasicType* output) const override;
};

class ASTOperator_t: public ASTExpress_t
{
private:

protected:
    char op;                    // 运算符
    ASTExpress_t *left, *right; // 左子式和右子式

public:
    ASTOperator_t(char op, ASTExpress_t* l, ASTExpress_t* r): op(op), left(l), right(r) {}
    virtual ~ASTOperator_t()
    {
        if (nullptr != this->left)
            delete this->left;

        if (nullptr != this->right)
            delete this->right;
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        bool res = false;

        if (nullptr != this->left)
            res |= this->left->isDirty();

        if (nullptr != this->right)
            res |= this->right->isDirty();

        return res;
    }
};

class ASTCompare_t: public ASTExpress_t
{
public:
    typedef enum
    {
        EQU,  // ==
        NEQU, // !=
        GEQU, // >=
        LEQU, //<=
        BAND, // &&
        BOR   // ||
    } Compare_op_t;

protected:
    Compare_op_t op;            // 运算符
    ASTExpress_t *left, *right; // 左子式和右子式

public:
    ASTCompare_t(Compare_op_t op, ASTExpress_t* l, ASTExpress_t* r): op(op), left(l), right(r) {}
    virtual ~ASTCompare_t()
    {
        if (nullptr != this->left)
            delete this->left;

        if (nullptr != this->right)
            delete this->right;
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        bool res = false;

        if (nullptr != this->left)
            res |= this->left->isDirty();

        if (nullptr != this->right)
            res |= this->right->isDirty();

        return res;
    }
};

class ASTCondition_t: public ASTExpress_t
{
private:

protected:
    ASTExpress_t *cond, *left, *right;

public:
    ASTCondition_t(ASTExpress_t* c, ASTExpress_t* l, ASTExpress_t* r): cond(c), left(l), right(r) {}
    virtual ~ASTCondition_t()
    {
        if (nullptr != this->cond)
            delete this->cond;

        if (nullptr != this->left)
            delete this->left;

        if (nullptr != this->right)
            delete this->right;
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        bool res = false;

        if (nullptr != this->left)
            res |= this->left->isDirty();

        if (nullptr != this->right)
            res |= this->right->isDirty();

        if (nullptr != this->cond)
            res |= this->cond->isDirty();

        return res;
    }
};

class ASTString_t: public ASTExpress_t
{
private:
    const char* str;

protected:

public:
    ASTString_t(const char* s): str(s) {}
    virtual ~ASTString_t()
    {
        if (nullptr != this->str)
            free(static_cast<void*>(const_cast<char*>(this->str)));
    }

    virtual void calculate(BasicType* output) const override
    {
        size_t* ptr = reinterpret_cast<size_t*>(output);
        *ptr = reinterpret_cast<size_t>(this->str); // 指针传递
    }
};

class ASTList_t: public ASTExpress_t
{
private:

protected:
    QList<ASTExpress_t*>* members;

public:
    ASTList_t(QList<ASTExpress_t*>* list): members(list) {}
    virtual ~ASTList_t()
    {
        if (nullptr != this->members) {
            for (auto pm : *members) delete pm;

            delete this->members;
        }
    }

    virtual void calculate(BasicType* output) const override;
    virtual bool isDirty(void) const override
    {
        if (nullptr != this->members) {
            for (auto exp : *this->members) {
                if (exp->isDirty())
                    return true;
            }
        }

        return false;
    }
};
